#pragma once
#include <jsoncpp/json/json.h>
#include <string>
#include <ctime>
#include <iostream>
#include <memory>

/*
    应用层自定义协议：约定双方通信的结构化字段
    1、请求Request类：协议中的有效载荷，由上层业务逻辑产生
    2、响应Response类：协议中的有效载荷，从协议报文中解包获取，对于解包要在上层解决粘包问题
    3、封装函数：对Request请求添加相应的协议报头，封装成请求报文
    4、解包函数：对响应报文进行解包，提取有效载荷Response
*/


namespace protocol_ns
{
    // 解决Tcp粘报问题：基于tcp协议，读到的报文可能是不完整的
    // （因为tcp是面向字节流，数据写到发送缓冲区之后，最后怎么发送什么时间发送取决于系统）

    // 报文 = 报头 + 有效载荷
    // 我们的报文：len + "\r\n" + "有效载荷" + "\r\n"，其中len充当协议报头
    std::string sep = "\r\n";
    std::string encoding(std::string &jsonstr) // 封装
    {
        std::string ret;
        ret += std::to_string(jsonstr.size());
        ret = ret + sep + jsonstr + sep;
        return ret;
    }

    std::string decoding(std::string &packstr) // 解包
    {
        // 从网络中接收到的packstr不一定是一个完整的报文，所以要处理
        // len
        // len\r\n
        // len\r\n有效载荷\r\n
        // len\r\n有效载荷\r\nlen\r\n有效载荷
        // len\r\n有效载荷\r\nlen\r\n有效载荷\r\nlen\r\n有效载荷\r\n
        // 等等各种情况
        size_t pos = packstr.find(sep);
        if (pos == std::string::npos)
            return std::string();

        std::string substr = packstr.substr(0, pos);
        if (substr.empty())
            return std::string();

        int len = std::stoi(substr);
        if (len <= 0)
            return std::string();

        int total = substr.size() + len + 2 * sep.size();
        if (packstr.size() < total)
            return std::string();

        std::string jsonstr = packstr.substr(pos + sep.size(), total);
        packstr.erase(0, total); // 将一个完整的格式化数据从流中去除，方便处理后面的
        return jsonstr;
    }

    class Request
    {
    public:
        Request()
        {
        }

        Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper)
        {
        }

        void serialized(std::string &jsonstr) // 序列化
        {
            // 1、转换成json格式
            Json::Value v;
            v["x"] = _x;
            v["y"] = _y;
            v["oper"] = _oper;

            // 2、序列化成字符串
            Json::FastWriter writer;
            jsonstr = writer.write(v);
        }

        void nonSerialized(std::string &jsonstr)
        {
            // 1、字符串反序列化成json格式数据
            Json::Value v;
            Json::Reader reader;
            reader.parse(jsonstr, v);

            // 2、json格式转自定义格式
            _x = v["x"].asInt();
            _y = v["y"].asInt();
            _oper = std::stoi(v["oper"].asString());
        }

    public:
        int _x;
        int _y;
        char _oper;
    };

    class Response
    {
    public:
        Response()
        {
        }

        Response(int result, int state) : _result(result), _state(state)
        {
        }

        void serialized(std::string &jsonstr)
        {
            // 1、转换成json格式
            Json::Value v;
            v["result"] = _result;
            v["state"] = _state;

            // 2、序列化成字符串
            Json::FastWriter writer;
            jsonstr = writer.write(v);
        }

        void nonSerialized(std::string &jsonstr)
        {
            // 1、字符串反序列化成json格式数据
            Json::Value v;
            Json::Reader reader;
            reader.parse(jsonstr, v);

            // 2、json格式转自定义格式
            _result = v["result"].asInt();
            _state = v["state"].asInt();
        }

        void debug()
        {
            std::cout << "result: " << _result << ", state: " << _state << std::endl;
        }

    public:
        int _result;
        int _state; // 表示状态：0正常，1除0，2模0，3其他错误
    };

    class Factory //工厂
    {
    public:
        Factory():_opers("+-*/%&^")
        {
            srand(time(nullptr));
        }
        std::shared_ptr<Request> productRequest()
        {
            int x = rand() % 100 + 1;
            int y = rand() % 100;
            char oper = _opers[rand() % _opers.size()];
            return std::make_shared<Request>(x, y, oper);
        }

    private:
        std::string _opers;
    };
}